package org.example.config;


import com.nimbusds.jose.JWSAlgorithm;
import org.example.security.AuthorizationManager;
import org.example.utils.KeysUtils;
import org.example.utils.RestUtils;
import org.example.utils.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
import org.springframework.security.oauth2.server.resource.web.access.server.BearerTokenServerAccessDeniedHandler;
import org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
import org.springframework.web.server.session.DefaultWebSessionManager;
import reactor.core.publisher.Mono;

import javax.crypto.spec.SecretKeySpec;

/**
 * 资源服务器配置
 */
@Configuration
@EnableWebFluxSecurity
public class ResourceServiceConfig {
    @Autowired
    private AuthorizationManager authorizationManager;

    @Bean
    public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity httpSecurity){
//        httpSecurity.oauth2ResourceServer()
//                .jwt()
//                .jwtAuthenticationConverter(jwtAuthenticationConverter())
//                .jwtDecoder(jwtDecoderBuilder());
//        httpSecurity.oauth2ResourceServer()
//                .opaqueToken()
//                .introspectionUri("http://127.0.0.1:9300/oauth/check_token")
//                        .introspectionClientCredentials("oauth","secret");
//
//        httpSecurity.oauth2ResourceServer().authenticationEntryPoint(authenticationEntryPoint());
//        httpSecurity.oauth2ResourceServer().bearerTokenConverter(new ServerBearerTokenAuthenticationConverter());
        httpSecurity.authorizeExchange()
//                .pathMatchers(ArrayUtil.toArray(whiteListConfig.getUrls(), String.class)).permitAll()
                .anyExchange().access(authorizationManager) //访问决策，既授权管理
                .and()
                .exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler()) // 处理未授权
                .authenticationEntryPoint(authenticationEntryPoint()) //处理未认证
                .and().csrf().disable();

        return httpSecurity.build();

    }

    /**
     * 未授权
     * 服务器访问被拒绝的处理程序
     */
    @Bean
    public ServerAccessDeniedHandler accessDeniedHandler(){
        return (exchange, e) -> {
            Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getResponse()))
                    .flatMap(response -> WebUtils.writeFailedToResponse(response, RestUtils.CLIENT_AUTHENTICATION_FAILED()));
            return mono;
        };
    }

    /**
     * 服务器身份验证入口点
     * token无效或者已过期自定义响应
     */
    @Bean
   public ServerAuthenticationEntryPoint authenticationEntryPoint() {
        return (exchange, e) -> {
            Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getResponse()))
                    .flatMap(response -> WebUtils.writeFailedToResponse(response, RestUtils.TOKEN_INVALID_OR_EXPIRED()));
            return mono;
        };
    }

    /**
     * @return
     * @link https://blog.csdn.net/qq_24230139/article/details/105091273
     * ServerHttpSecurity没有将jwt中authorities的负载部分当做Authentication
     * 需要把jwt的Claim中的authorities加入
     * 方案：重新定义R 权限管理器，默认转换器JwtGrantedAuthoritiesConverter
     */
    @Bean
    public Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        jwtGrantedAuthoritiesConverter.setAuthorityPrefix(KeysUtils.AUTHORIZATION_PREFIX); //设置前置
        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName(KeysUtils.JWT_AUTHORITIES_KEY);
        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
        converter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
       return new ReactiveJwtAuthenticationConverterAdapter(converter);
    }

    /**
     * 设置jwt解密秘钥
     * @return
     */
    @Bean
    public ReactiveJwtDecoder jwtDecoderBuilder(){
        SecretKeySpec keySpec = new SecretKeySpec(KeysUtils.AUTHORIZATION_SECRET.getBytes(), JWSAlgorithm.HS256.getName());
        return NimbusReactiveJwtDecoder.withSecretKey(keySpec).build();
    }

}
